import os.path
import threading
import time
from datetime import datetime
from fastapi import APIRouter

from zn.common.router.root import app
from zn.common.component.component import TComponent , componentManager
from zn.common.component.db import TDB
from zn.common.utils.mqtt_utils import TMqtt
from zn.common.utils.mddbus_utils import TModbus
from zn.common.utils.http_utils import THttpUtils

class TTer_DTUMB_Temperture_Task:
    def __init__(self):
        self.taskCode=""
        self.taskInfo ={}
class TTer_DTUMB_Temperture(TComponent):
    def __init__(self , _mananger):
        super().__init__(_mananger)
        self.channels = {}
        self.mqttParams = {}
        self.mqtts = {}
        self.variants = {}
        self.buffer ={}
        self.values ={}
    @property
    def terCode(self):
        res = ""
        try:
            res = self.settings['terCode']
        except Exception as er:
            self.manager.error(er)
        return res
    @property
    def dbCode(self):
        res = ""
        try:
            res = self.settings['dbCode']
        except Exception as er:
            self.manager.error(er)
        return res
    @property
    def dataPath(self):
        res = ""
        try:
            res = self.settings['dataPath']
        except Exception as er:
            self.manager.error(er)
        return res
    @property
    def db(self)->TDB:
        dbCode= self.settings['dbCode']
        return  componentManager.getComponent(dbCode)
    def start(self):
        super().start()
        try:
            for ch in self.channels.values():
                ( threading.Thread(target= self.channelCollect , args=[ch] , daemon=True)).start()
        except Exception as er:
            self.manager.error(er)
    def init(self):
        super().init()
        try:
            self.loadParams()
        except Exception as er:
            self.manager.error(er)
    def stop(self):
        super().stop()
        try:
            pass
        except Exception as er:
            self.manager.error(er)
    def getStatus(self):
        res = super().getStatus()
        try:
            res['status']={
                "time": time.time()
            }
        except Exception as er:
            self.manager.error(er)
        return res
    def channelCollect(self , chInfo):
        try:
            mqsvrId = chInfo['mqsvrId']
            mqclient = self.getMqtt(mqsvrId)
            topic = chInfo['downTopic']
            upTopic = chInfo['upTopic']
            while 1>0 :
                time.sleep(1)
                for  var in chInfo['vars'].values() :
                    timeNow = time.time()
                    dltTime = timeNow - var['lastTime']
                    thresholdTime = 60*30
                    if dltTime> thresholdTime:
                        try:
                            var['lastTime'] = timeNow
                            cmdBytes = var['cmdBytes']
                            mqclient.client.publish(topic , cmdBytes)
                            print(f"send bytes varId:" ,{var['varId']} ,{chInfo['channelName']}, {var['deviceName']},{var['deviceTypeCode']}, [hex(x) for x in cmdBytes])
                            bufferKey = f"{upTopic}/{cmdBytes[0]}/{cmdBytes[1]}"
                            self.buffer[bufferKey] = {
                                "var":var ,
                                "success":False ,
                                "dataBytes":None
                            }
                            dltTime = 0
                            nowTime = time.time()
                            success = False
                            varId = var['varId']
                            if varId==170 or varId==175:
                                print(var)
                            while dltTime< 5:
                                time.sleep(1)
                                if self.buffer[bufferKey]['success'] :
                                    success = True
                                    break
                                dltTime = time.time() - nowTime
                            if success :
                                print(f"rec bytes :{[hex(x) for x in self.buffer[bufferKey]['dataBytes'] ]}")
                                self.updateVariantValue(var, self.buffer[bufferKey]['dataBytes'])
                        except Exception as erItem :
                            print(erItem)
        except Exception as er:
            self.manager.error(er)
    def loadParams(self):
        try:
            datakey = "ter/ter_dtu_modbus/params"
            queryRes = self.db.queryByKey(   datakey , {"terCode": self.terCode})
            if queryRes['queryStatus'] ==1 :
                channels = queryRes['datasetList'][0]
                variants = queryRes['datasetList'][1]
                mqs = queryRes['datasetList'][2]
                for mq in mqs:
                    mq['subTopics']=[]
                    self.mqttParams[mq['mqsvrId']] = mq
                for ch in channels:
                    ch["vars"] ={}
                    self.channels[ch['channelId']] = ch
                    mqsvrId = ch['mqsvrId']
                    upTopic = ch['upTopic']
                    if mqsvrId in self.mqttParams.keys():
                        self.mqttParams[mqsvrId]['subTopics'].append(upTopic)
                for var in variants:
                    var['lastTime'] = 0
                    varId = var['varId']
                    chId = var['channelId']
                    self.variants[varId] = var
                    if chId in self.channels.keys():
                        chInfo = self.channels[chId]
                        funCode = int(var['funCode'])
                        unitId = int(var['unitId'])
                        regAddr = var['addr0']
                        regNum = var['len0']
                        cmdBytes = TModbus.getReadCmdBytes(unitId, funCode, regAddr, regNum)
                        var['cmdBytes'] = cmdBytes
                        chInfo['vars'][varId] = var
                print(self.channels)
        except Exception as er:
            self.manager.error(er)
    def getMqtt(self , mqttId):
        res = None
        try:
            if mqttId in self.mqtts.keys():
                res = self.mqtts[mqttId]
            elif mqttId in self.mqttParams.keys():
                mqPs = self.mqttParams[mqttId]
                client = TMqtt()
                client.mqttCode = mqttId
                client.mqttCode = mqttId
                client.settings = {
                    "host": mqPs['host'] ,
                    "port": mqPs['port'] ,
                    "uid": mqPs['uid'] ,
                    "pwd": mqPs['pwd'] ,
                    "subTopics": mqPs['subTopics'] ,
                }
                def onMsg(message):
                    try:
                        print(f"rec modbus :" , [hex(x) for x in message.payload])
                        upTopic = message.topic
                        cmdBytes = message.payload
                        pgkFlag = TModbus.isResponsePgk(cmdBytes)
                        if pgkFlag :
                            bufferKey = f"{upTopic}/{cmdBytes[0]}/{cmdBytes[1]}"
                            if bufferKey in self.buffer.keys():
                                buf = self.buffer[bufferKey]
                                buf['success'] = True
                                buf['dataBytes'] = (list(cmdBytes))[3:-2]

                    except Exception as erMsg:
                        print(erMsg)
                client.onMsg = onMsg
                self.mqtts[mqttId] = client
                client.connect()
                res = client
        except Exception as er:
            self.manager.error(er)
        return res
    def updateVariantValue(self , var , dataBytes):
        try:
            r0 = var['r0']
            r1 = var['r1']
            v = int.from_bytes(dataBytes , byteorder='big')
            value = v*r0*r1
            var['values'] ={
                "t":time.time() ,
                "v":value
            }
            self.saveVariantValue(var)
            postRes = self.postVariant(  var)
            self.manager.error(postRes)
        except Exception as er:
            self.manager.error(er)
    def saveVariantValue(self , var ):
        try:
            dataPath = self.settings['dataPath']
            sysCode = var['sysCode']
            deviceCode = var['deviceCode']
            varId = var['varId']
            day =  datetime.now().strftime("%Y%m%d")
            dirName = f"{dataPath}/dataLog/{sysCode}/{varId}"

            if not os.path.exists(dirName):
                os.makedirs(dirName , 0x777)
            fn = os.path.join(dirName , f"{day}.csv")
            content = f"{var['varId']},{var['values']['t']},{var['values']['v']}\n"
            if os.path.exists(fn):
                with open(fn ,'a' , encoding='utf-8') as f:
                    f.write(content)
            else:
                with open(fn ,'w' , encoding='utf-8') as f:
                    f.write(content)



        except Exception as er:
            self.manager.error(er)
    def getObjs(self):
        res =[]
        try:
            dataKey = "ter/ter_dtu_modbus/objs"
            ps={
                "terCode" : self.terCode
            }
            queryRes = self.db.queryByKey(dataKey , ps)
            res = queryRes['datasetList']
        except Exception as er:
            self.manager.error(er)
        return res
    def getRealValues(self):
        res = {}
        try:
            for var in self.variants.values():
                if 'values' in var.keys():
                    varId = var['varId']
                    res[varId] = var['values']
        except Exception as er:
            self.manager.error(er)
        return res
    def getVarValues(self , varId , day):
        res = ""
        try:
            if varId in self.variants.values():
                var = self.variants[varId]
                fn = f"{self.settings['dataPath']}/dataLog/{var['sysCode']}/{varId}/{day}.csv"
                if os.path.exists(fn):
                    with open( fn ,'r' , encoding='utf-8') as f:
                        res = f.read()
        except Exception as er:
            self.manager.error(er)
        return res
    def postVariant(self , var):
        res = ""
        try:
            url = var['dataSvrUrl']
            varInfo ={
                "varId" : var['varId'] ,
                "sysCode" : var['sysCode'] ,
                "deviceCode" : var['deviceCode'] ,
                "t" : var['values']['t'] ,
                "v" : var['values']['v']
            }
            ps ={
                "variantList":[varInfo]
            }
            res = THttpUtils.httpPost(url , ps )
        except Exception as er:
            self.manager.error(er)
        return res

componentManager.registComponentType('TTer_DTUMB_Temperture', TTer_DTUMB_Temperture)


router = APIRouter()


@router.get("/getobjs")
async def router_getObjs( terCode:str ):
    res ={
        "status":0,
        "result":None
    }
    try:
        ter:TTer_DTUMB_Temperture = componentManager.getComponent(terCode)
        if ter!=None:
            res['result'] = ter.getObjs()
            res['status'] = 1
    except Exception as er :
        componentManager.error(er)
    return res


@router.get("/getRealValues")
async def router_getRealValues( terCode:str ):
    res ={
        "status":0,
        "result":None
    }
    try:
        ter:TTer_DTUMB_Temperture = componentManager.getComponent(terCode)
        if ter!=None:
            res['result'] = ter.getRealValues()
            res['status'] = 1
    except Exception as er :
        componentManager.error(er)
    return res


@router.get("/getVarValues")
async def router_getVarValues( terCode:str , varId : int , day:str):
    res ={
        "status":0,
        "result":None
    }
    try:
        ter:TTer_DTUMB_Temperture = componentManager.getComponent(terCode)
        if ter!=None:
            res['result'] = ter.getVarValues(varId=varId , day=day)
            res['status'] = 1
    except Exception as er :
        componentManager.error(er)
    return res
app.include_router(router, prefix="/temperture" ,tags=['temperture'])